package main

import (
	"context"
	"fmt"
	"time"
)

func foo(ctx context.Context) {
	ctx, cancelCtx := context.WithTimeout(ctx, 1500*time.Millisecond)

	// 不一定是必需的，因为另一个调用将始终运行，但保留它可能很有用，以防将来有任何 return 语句导致它被错过。当上下文在截止日期后被取消时，仍然需要调用取消函数来清理已使用的任何资源，因此这更像是一种安全措施。
	defer cancelCtx()

	printCh := make(chan int)
	go bar(ctx, printCh)

	for num := 1; num <= 3; num++ {
		select {
		case printCh <- num:
			time.Sleep(time.Second * 1)
		case <-ctx.Done():
			break
		}
	}

	cancelCtx()

	time.Sleep(time.Millisecond * 100)

	fmt.Printf("foo finished\n")
}

func bar(ctx context.Context, printCh <-chan int) {
	for {
		select {
		case <-ctx.Done():
			if err := ctx.Err(); err != nil {
				fmt.Printf("bar err: %s\n", err)
			}
			fmt.Printf("bar finished\n")
			return
		case num := <-printCh:
			fmt.Printf("bar: %d\n", num)
		}
	}
}

func main() {
	ctx := context.Background() // 创建空的上下文
	foo(ctx)
}
